package Harmonisation.CreationDuChant;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import Harmonisation.Accord;
import Harmonisation.Note;

public class GrapheAccords {
	private static ArrayList<Accord> listAccord;
	private static Hashtable<String, Accord> hashAccord = new Hashtable<String, Accord>() {
		private static final long serialVersionUID = 8085905424403384730L;

		{
			/* creation des accords */
			Accord accord1 = new Accord("do", "mi", "sol", "i");
			Accord accord2 = new Accord("re", "fa", "la", "ii");
			Accord accord3 = new Accord("mi", "sol", "si", "iii");
			Accord accord4 = new Accord("fa", "la", "do", "iv");
			Accord accord4b = new Accord("fa", "la", "do", "ivb");
			Accord accord5 = new Accord("sol", "si", "re", "v");
			Accord accord6 = new Accord("la", "do", "mi", "vi");
			Accord accord7 = new Accord("si", "re", "fa", "vii");

			/* creation du graphe oriente */
			accord1.getEnchainementPossible().add(accord1);
			accord1.getEnchainementPossible().add(accord2);
			accord1.getEnchainementPossible().add(accord3);
			accord1.getEnchainementPossible().add(accord4);
			accord1.getEnchainementPossible().add(accord5);
			accord1.getEnchainementPossible().add(accord6);
			accord1.getEnchainementPossible().add(accord7);

			accord2.getEnchainementPossible().add(accord2);
			accord2.getEnchainementPossible().add(accord5);
			accord2.getEnchainementPossible().add(accord7);

			accord3.getEnchainementPossible().add(accord2);
			accord3.getEnchainementPossible().add(accord3);
			accord3.getEnchainementPossible().add(accord4);
			accord3.getEnchainementPossible().add(accord5);
			accord3.getEnchainementPossible().add(accord6);
			accord3.getEnchainementPossible().add(accord7);

			accord4.getEnchainementPossible().add(accord1);
			accord4.getEnchainementPossible().add(accord2);
			accord4.getEnchainementPossible().add(accord3);
			accord4.getEnchainementPossible().add(accord4);
			accord4.getEnchainementPossible().add(accord5);
			accord4.getEnchainementPossible().add(accord6);
			accord4.getEnchainementPossible().add(accord7);

			accord4b.getEnchainementPossible().add(accord1);
			accord4b.getEnchainementPossible().add(accord4b);

			accord5.getEnchainementPossible().add(accord1);
			accord5.getEnchainementPossible().add(accord3);
			accord5.getEnchainementPossible().add(accord5);
			accord5.getEnchainementPossible().add(accord6);
			accord5.getEnchainementPossible().add(accord4b);

			accord6.getEnchainementPossible().add(accord2);
			accord6.getEnchainementPossible().add(accord3);
			accord6.getEnchainementPossible().add(accord4);
			accord6.getEnchainementPossible().add(accord5);
			accord6.getEnchainementPossible().add(accord6);

			accord7.getEnchainementPossible().add(accord1);
			accord7.getEnchainementPossible().add(accord3);
			accord7.getEnchainementPossible().add(accord7);
			// Premiere octave
			put("i", accord1);
			put("ii", accord2);
			put("iii", accord3);
			put("iv", accord4);
			put("v", accord5);
			put("vi", accord6);
			put("vii", accord7);
			put("ivb", accord4b);
		}
	};

	public GrapheAccords() {
		setListAccord(new ArrayList<Accord>());

		getListAccord().add(GrapheAccords.hashAccord.get("i"));
		getListAccord().add(GrapheAccords.hashAccord.get("ii"));
		getListAccord().add(GrapheAccords.hashAccord.get("iii"));
		getListAccord().add(GrapheAccords.hashAccord.get("iv"));
		getListAccord().add(GrapheAccords.hashAccord.get("v"));
		getListAccord().add(GrapheAccords.hashAccord.get("vi"));
		getListAccord().add(GrapheAccords.hashAccord.get("vii"));
		getListAccord().add(GrapheAccords.hashAccord.get("ivb"));
	}

	/**
	 * 
	 * @param voixSoprano
	 *            est la liste de note
	 * @return renvoie une arraylist<arraylist<accord>> qui décrit a chaque temps, quel accord il est possible de jouer
	 */
	public ArrayList<ArrayList<Accord>> getAccordPossibleSopranoAChaqueTemps(ArrayList<Note> voixSoprano) {
		/* Mise en place des accords possibles a chaque temps selon la ligne de note de la voix soprano */
		ArrayList<ArrayList<Accord>> accordPossibleSoprano = new ArrayList<ArrayList<Accord>>();
		Iterator<Note> it = voixSoprano.iterator();
		Note note = null;
		int tempsNoteSoprano = 0;
		while (it.hasNext() || tempsNoteSoprano > 0) {
			if (tempsNoteSoprano == 0 && it.hasNext()) {
				note = it.next();
				tempsNoteSoprano = note.getTemps();
			}
			tempsNoteSoprano--;
			ArrayList<Accord> accordPossiblePourNoteCourante = new ArrayList<Accord>();
			/* On remplie maintenant les accords possible pour la note en la comparant aux noeuds du graphe */
			Iterator<Accord> it2 = getListAccord().iterator();
			Accord accord;
			while (it2.hasNext()) {
				accord = it2.next();
				if (accord.appartientALAccord(note)) {
					accordPossiblePourNoteCourante.add(accord);
				}
			}
			accordPossibleSoprano.add(accordPossiblePourNoteCourante);/* on ajoute un arraylist contenant tout les accords possible pour la note soprano en cours */
		}

		regle4(accordPossibleSoprano);
		return accordPossibleSoprano;
	}

	private void regle4(ArrayList<ArrayList<Accord>> harmonisationPossible) {/* Methode qui retire les enchainement commencant par ivb ou finissant par ivb */
		if (harmonisationPossible.size() > 0) {
			harmonisationPossible.get(0).remove(GrapheAccords.hashAccord.get("ivb"));
			harmonisationPossible.get(harmonisationPossible.size() - 1).remove(GrapheAccords.hashAccord.get("ivb"));
		}
	}

	public static ArrayList<Accord> getListAccord() {
		return listAccord;
	}

	public void setListAccord(ArrayList<Accord> listAccord) {
		GrapheAccords.listAccord = listAccord;
	}

}
